home *** CD-ROM | disk | FTP | other *** search
- ************
- The Debugger
- ************
-
- Debugging consists mainly of locating the area where a problem occurs.
-
- Doing this sometimes requires additional information about program
- execution, and in these cases the custom HeliOS debugger is very useful.
-
- Beware, however, of the common mistake of using a debugger to generate
- a lot of extra information which in fact confuses the issue and makes
- the task of debugging harder than it need be.
-
- Often the simple use of output statements within a program, along with
- careful inspection and analysis of the code, is all that is required.
-
- HeliOS has a powerful debug facility which can be user-customised to do
- almost anything. This debugger is deceptively simple but very powerful:
- it effectively allows you to step through your code checking any aspect
- of the system as you go and carrying out any procedure required.
-
- You enter DEBUG mode when you press the "DBug" button in the Interpreter,
- and you are then in DEBUG mode until you press the same button again.
-
- In DEBUG mode you lose the "Stack Display" but gain a few new buttons.
-
- The DEBUG functions will be described below in more detail, but first here
- is a quick overview of debugger operation.
-
- In DEBUG mode the Interpreter goes through a DEBUG "gate" each time it
- executes COLON/SEMICOLON threading operations. At this point you can have
- the debugger run your own user-definable HeliOS mini-program(s) to analyse
- what your code is doing and print the results for you to see.
-
- You can change the debug code at any point in the program, and even have
- the debug code change its own subsequent execution function depending on
- program action.
-
- You can, for example, pause the program, display variables, dump memory,
- single step, wait on variable states.........whatever you choose.
-
- The debugger has a STEP function which allows you to specify how many times
- to skip between actual debug operations. By default you will debug every
- word, but you can change this interactively while your program is running.
-
- You can send debug output to the screen or to the "Out" buffer, and while
- you are debugging you can send the normal output of the program either to
- the screen or the "Out" buffer. These two options are in the form of a
- double toggle - you cannot have debugger AND program output to either one
- single output stream, for obvious reasons of general confusion.......
-
- The debugger has a fully interactive mode of operation, which means that
- you can press any of the debugger control buttons while the program is
- executing. Thus you can press "Dump" to dump a predefined area of memory
- at any time while the program executes. This will halt program execution
- as soon as you hit the "Dump" button, and resume when the dump is finished.
-
- You can halt a program by using the debug control panel, or by setting
- "breakpoints". The breakpoint mechanism is very flexible, in that you
- can control the debug functions either from the control panel buttons or
- from programmable functions within the code.
-
- At any point you can temporarily pause the debug session by using the
- <Space> bar, and you can abort at any time by pressing <Esc>.
-
- This is very much a user-definable debugger, which is important since
- debugging requires a very flexible approach for particular contingencies.
-
- The debug functions include the ability to list to screen a full nested
- display of the names of the HeliOS words in any current "thread".
-
- By default the debugger runs a very simple standard function which lists
- all the levels of the current execution thread and displays stack contents.
-
- **************************
- Listing the current thread
- **************************
-
- The debug control word SHOWDEBUGWORD can display the current execution word
- or the complete current execution thread.
-
- To understand this, you need to see how a threaded interpretive language
- such as HeliOS strings together nested command words.
-
- Let us assume that you create a word called PRINTHELLO, like this:
-
- : PRINTHELLO ." Hello " ;
-
- Let us assume then that you create a word called SHOWHELLO, like this:
-
- : SHOWHELLO 20 20 CURPUT PRINTHELLO ;
-
- Let us assume then that you create a word called SHOWREDHELLO, like this:
-
- : SHOWREDHELLO 6 FPENSET SHOWHELLO ;
-
- Let us assume then that you create a word called HELLOFRIEND, like this:
-
- : HELLOFRIEND SHOWREDHELLO ." Friend!" ;
-
- Now let us look what happens when you execute HELLOFRIEND:
-
- First the interpreter gets the word HELLOFRIEND and starts to interpret it.
-
- The interpreter finds a new word SHOWREDHELLO, so it remembers where it was
- in its execution of the word HELLOFRIEND and tries to interpret the new
- word SHOWREDHELLO.
-
- The interpreter is now at a second nested level, and the current thread
- consists of the two words HELLOFRIEND and SHOWREDHELLO.
-
- Now the interpreter goes into the word SHOWREDHELLO and starts to interpret
- it. Here it will encounter a few execution commands for 6 FPENSET followed
- by your word SHOWHELLO.
-
- The interpreter has now found yet another a new word SHOWHELLO, so it once
- again remembers where it was in all the previous threaded words and starts
- to interpret SHOWHELLO.
-
- In SHOWHELLO, after the cursor positioning commands the interpreter finds
- yet another of your words, called PRINTHELLO.
-
- Once again the interpreter remembers where it was and tries to interpret
- the latest word PRINTHELLO.
-
- The word PRINTHELLO has a simple execution result and requires with no
- further threading, so now the interpreter goes back one level and continues
- where it left off on the previous threaded command SHOWHELLO.
-
- The interpreter will now work its way back out through the thread until
- all words have completed.
-
- When the interpreter was executing PRINTHELLO, the full thread would look
- like this, with a depth of four words:
-
- HELLOFRIEND SHOWREDHELLO SHOWHELLO PRINTHELLO
-
- The debugger would by default use the debug control word SHOWDEBUGWORD to
- display the full thread of the current execution word at each threading
- point.
-
- Thus if you were to debug the word HELLOFRIEND you would see a series of
- statements displaying the threading, step by step, which at one point
- would contain "HELLOFRIEND SHOWREDHELLO SHOWHELLO PRINTHELLO" .
-
- Try this in the interpreter, making sure that output is enabled to both the
- screen AND the buffer. Allow the execution of the word HELLOFRIEND to
- complete, then look at the results in the "Out" editor.
-
- You will notice that the word LIT appears every time HeliOS handles a pure
- numeric value on the stack.
-
- You will also notice some new words used to actually print to the screen.
-
- One of these words is called NONAME, which means that it is an internal
- HeliOS word with no vocabulary entry. There are many of these words with
- no user name, so in many cases your debug thread displays will contain
- multiple instances of words with NONAME. Do not worry about this.
-
- In particular, you fill find NONAME cropping up often when executing core
- HeliOS words rather than your own constructed threads.
-
- Careful examination of the full thread display in the "Out" editor will
- allow you to determine exactly which word is executing at any time and
- what the stack contains at this point.
-
-
- ******************
- Using the debugger
- ******************
-
- By default the debugger has a very simple debug execution function.
-
- If you enter DEBUG mode without setting your own debug function, the
- sytem will execute the default debug function at every threading point.
-
- The default debug function will, at each threading point:
-
- 1. Print out stack contents in red
-
- 2. Print out in black a list of the current thread
-
- Pressing the <Space> bar will pause the debug operation.
-
- Pressing <Space> a second time will restart debugging.
-
- Pressing <Esc> will abort debugging at any time.
-
- Use the thread display to determine exactly which part of your code is
- currently executing.
-
- The simple stack display used by default may be enough in many cases, but
- remember that you can create your own debug functions to check memory
- locations, print variables, etc.
-
- You can write debug words to do whatever you like, and you can use the
- debug control words listed below to control the action of the debugger
- from within your own debug software, allowing great flexibility.
-
- The rest is up to you, and how you wish to approach any particular debug
- task.
-
- ****************************
- Why NOT to use the debugger!
- ****************************
-
- Strictly speaking, using a debugger is a matter of personal preference,
- but in most cases you can debug code more quickly and efficiently by
- the intelligent use of print statements from within your code combined with
- the use of WAITSPACE commands to allow you to step through your code as it
- is executing.
-
- This can be far quicker and simpler than using a debugger, and we recommend
- that you avoid getting too involved with using the debugger unless you
- really need its powerful capabilities to crack a very difficult bug.
-
- You will make more progress in understanding your code if you undertake
- to find most bugs by careful inspection of your code along with the display
- of vital parameters as your program executes. In this way you become more
- expert in how your own code functions rather than in the intricacies of
- setting up complex debugging procedures.
-
- Of course, many programmers just love setting up fantastic sophisticated
- debug capabilities just for the sake of the feeling of power they get
- by squeezing alarming amounts of esoteric information from recalcitrant
- and malicious computers. This can be great fun of course, and constructing
- a subtle and cunning debug system to entrap a really nasty bug can be very
- satisfying in its own right.
-
- ****************************************************
- A few simple hints on debugging without the debugger
- ****************************************************
-
- HeliOS may indeed have a very powerful user-configurable debugger, but for
- most debugging you should never need to use it! The following hints should
- be taken as general programming guidelines, and intelligent programming is
- preferable to reliance on the debugger.
-
- There are a few simple techniques which, combined with sensible programming
- strategies (for example, do not write 200k of source code altogether with
- no testing then expect it to work instantly...), will enable you to debug
- code very simply.
-
- When a bug occurs the program will often (probably!) crash.
-
- The first stage of debugging is to find exactly at what point in the code
- the program goes wrong.
-
- One good simple debugging technique is to put a simple repetitive "pause
- and print" debug line into the code which allows you to step through the
- program slowly until the point where things go wrong.
-
- This "pause and print" line should display the stack status and wait for
- the space bar to be pressed.
-
- Something like the following will do nicely:
-
- ." Now doing xxxxx. Stack reads: " .S ." <SPACE> to continue" WAITSPACE CR
-
-
- A few of these lines included in your code will give you a sequential
- talk-through until the crash point is reached.
-
- Having written the program yourself you should be able to work out quite
- well just where in the execution of your code the fault is happening.
-
- Once you know where in the code the problem lies, intelligent examination
- of your code in combination with all the available "clues" will generally
- reveal the trouble quite easily.
-
- Start with the high level code first and then work into your subroutines:
- in this way you can home in on the actual fault. It is good practice to
- check each subroutine thoroughly as it is completed, but nevertheless the
- most unexpected results can occur when even apparently sound subroutines
- are used together in complex ways.
-
- The stack status message debug line suggested above will probably mess up
- your program's screen display, but that does not really matter in a debug
- operation.
-
- Always check for stack aberrations first. Be aware of what the stack should
- be reading and check your debug stack readouts scrupulously.
-
- If you like, include DUMP commands in your debug instructions to dump areas
- of memory for careful scrutiny. Displaying variables is also useful, as is
- the creation of special debug "flag" variables which you can use to warn
- you of various internal states of your program.
-
- There are so many ways for code to fail it is impossible to cover all the
- aspects of debugging. Debugging is a very intuitive thing and everyone
- has very personal preferences.
-
- The main thing is to never assume ANYTHING to be OK without double checking,
- and be prepared to be patient and check EVERYTHING relating to your problem
- with an open mind.
-
- Check your stack dumps minutely, dump and also check any areas of memory
- you think may be suspect, check variable values by including them in your
- debug lines where appropriate.
-
- One big source of trouble is using address pointers which should really be
- pointing at something useful like a screen structure address, but actually
- contain zero. A golden rule on a multitasking machine like the Amiga is
- never to assume that an allocation or opening routine must always succeed.
- Always check to see if everything has opened correctly, and always take
- care to initialise all fields of data structures correctly.
-
-
- *******
- Warning
- *******
-
- Sometimes using the debugger can have unpredictable results with certain
- types of code, so use it carefully and ensure that your work is saved
- before starting to debug complex code.
-
- You may often find that you want to debug software where the screen output
- of the debugger will cause conflicts with the program execution. In these
- cases you may wish to supply your own debug function or switch off output
- to the screen.
-
- It is a good idea to always switch off the debugger except when you are
- actually using it.
-
-
- *****************
- Debugger controls
- *****************
-
- *****************
- The "DBug" button
- *****************
-
- This changes the stack display bar into a set of debugger control buttons
- and simultaneously enters debug mode. You will then be in debug mode until
- you press the "DBug" button again, which reverts to normal interpretation.
-
-
- Debug control buttons:
-
- *************
- Screen Output
- *************
- - These buttons toggle debugger output streams
- *************
- Buffer Output
- *************
-
- The idea here is that when in debug mode, your program's normal screen
- output will be stopped, and the screen will be used by the debugger to
- print debug messages. Similarly the "Out" buffer will get debug output.
-
- If you switch off either of the Screen/Buffer output buttons, the normal
- program output will be sent to that output stream rather than the debug
- output. Thus you can choose which output you want to see, and can view
- one output while sending the other to the "Out" buffer.
-
- These buttons can be pressed as your program is executing so that you can
- alternate between output modes at will during a debugging session. This
- gives great flexibility to the system.
-
- What is perhaps even more useful is that the output streams can be changed
- under program control by your debug routines within the executing program.
-
- This system gives you a lot of control and choice over the posting of
- debugger information.
-
- **********************************************
- The "Step" button and associated string gadget
- **********************************************
-
- The step string gadget lets you set how many times the debugger will "skip"
- between calls to the debug routines. A setting of "1" will cause the debug
- code to be run for every threaded word, a setting of "4" will sample every
- fourth threading etc.
-
- Again this can be altered at will as the program executes, and can also be
- changed by the debug software. Thus you could insert debug routines which
- step through certain sections of code in large jumps until a "vital" part
- of the program is reached, whereupon the debugger could be made under the
- control of software to "automatically" change to single stepping.
-
- The "Step" button, if switched "On", will cause the software to pause at
- each debug entry point rather than free running. Thus you can skip parts
- of a program and return to debug "paused" mode by entering a certain value
- into the string gadget, setting "Step" to "On", then pressing "Run".
-
- Again this can be done interactively while the program is executing or
- from within the software under debug program control.
-
- ****************
- The "Run" button
- ****************
-
- This starts the program executing after you have paused within debug mode.
-
- This function is also available from program control.
-
- ******************
- The "Pause" button
- ******************
-
- This stops the program executing and pauses within debug mode.
-
- Pressing the <Space> bar will also pause the debug operation.
-
- Pressing <Space> a second time will restart debugging.
-
- Pressing <Esc> will abort debugging at any time.
-
- This function is also available from program control.
-
-
- ******************
- The "Abort" button
- ******************
-
- This aborts the debug session and quits the program.
-
- Pressing <Esc> will abort debugging at any time.
-
- Pressing the <Space> bar will pause the debug operation.
-
- Pressing <Space> a second time will restart debugging.
-
- This function is also available from program control.
-
-
- **********************************************
- The "Dump" button and associated string gadget
- **********************************************
-
- This button lets you set up an address for a memory dump which can be
- carried out by pressing the "Dump" button at any time while the program
- is executing.
-
- This function is also available from program control.
-
-
- **********************
- Debugger control words
- **********************
-
- There are several HeliOS words which control the action of the debugger
- from within your program. These words can be used to set up breakpoints
- and conditional debugging etc.
-
-
- ********
- SETDEBUG ( cfa [or 0] - - - )
- ********
-
- Used in the form:
-
- FIND MYDEBUGWORD SETDEBUG -> Makes MYDEBUGWORD the subsequent debug action
-
- 0 SETDEBUG -> Restores the system default debug action
-
-
- *************
- GETDEBUGLEVEL ( - - - n1 )
- *************
-
- Returns n1, the current depth, or level, of the threaded interpreter.
- You can use this word to determine how many nested levels deep your
- current execution word lies.
-
- *************
- SHOWDEBUGWORD ( n1 - - - )
- *************
-
- This word will print to screen the name of the HeliOS word which lies
- at level n1 in the current execution thread.
-
- If you use a value of "n1 = -1", a full list of the full execution thread
- will be printed. This is the default used by the system debug word.
-
- *************
- SETDEBUGPAUSE ( - - - )
- *************
-
- Acts like the debug "Pause" button to enter debugger paused state.
-
- *************
- SETDEBUGABORT ( - - - )
- *************
-
- Acts like the debug "Abort" button to abort the debug session.
-
- **************
- SETDEBUGSCREEN ( n1 - - - ) where n1 = switch (1 for "On", 0 for "Off")
- **************
-
- Acts like the debug "Screen" button to toggle screen output mode.
-
- **************
- SETDEBUGBUFFER ( n1 - - - ) where n1 = switch (1 for "On", 0 for "Off")
- **************
-
- Acts like the debug "Buffer" button to toggle buffer output mode.
-
-
- *********
- SETDEBUG# ( n1 - - - )
- *********
-
- Inserts a number n1 into the debug step number string gadget and updates
- the step number.
-
-
- ************
- SETDEBUGSTEP ( n1 - - - ) where n1 = switch (1 for "On", 0 for "Off")
- ************
-
- Sets the current status of the debug "Step" button.
-